/**
 * 
 */
package br.edu.unifei.cct720.trabalho05.utils.sombreamento;

import java.util.Random;

import br.edu.unifei.cct720.trabalho05.utils.constantes.Constantes;
import br.edu.unifei.cct720.trabalho05.utils.formas.Circulo;
import br.edu.unifei.cct720.trabalho05.utils.formas.FormaGeometrica;
import br.edu.unifei.cct720.trabalho05.utils.formas.Reta;
import br.edu.unifei.cct720.trabalho05.utils.formas.Retangulo;
import br.edu.unifei.cct720.trabalho05.utils.formas.Setor;
import br.edu.unifei.cct720.trabalho05.utils.ponto.Ponto;
import br.edu.unifei.cct720.trabalho05.utils.ponto.Pontos;

/**
 * Classe responsavel por realizar as acoes de sombreamento
 * sobre uma determinada forma geometrica
 * 
 * @author fknappe
 *
 */
public class Sombreamento {

	// Declaracao das variaveis locais
	private Random random;

	/**
	 * Construtor
	 */
	public Sombreamento() {
		random = new Random();
	}	

	/**
	 * Metodo responsavel por selecionar o tipo de sombreamento que sera aplicado sobre a forma
	 * geometrica
	 * 
	 * @param FormaGeometrica forma
	 * @param String tipoSombreamento
	 * @param double fator
	 * 
	 * @return Pontos
	 */
	public Pontos criaSombreamento(FormaGeometrica forma, String tipoSombreamento, double fator) {
		Pontos pontos = new Pontos();

		if (forma instanceof Retangulo) {
			pontos = criaSombreamentoRetangulo((Retangulo) forma, tipoSombreamento, fator);
		} else if (forma instanceof Setor) {
			pontos = criaSombreamentoSetor((Setor) forma, tipoSombreamento, fator);
		}

		return pontos;
	}

	/**
	 * Metodo responsavel por aplicar o sombreamento sobre um retangulo
	 * 
	 * @param Retangulo retangulo
	 * @param String tipoSombreamento
	 * @param double fator
	 * 
	 * @return Pontos
	 */
	private Pontos criaSombreamentoRetangulo(Retangulo retangulo, String tipoSombreamento, double fator) {
		Pontos pontos = new Pontos();

		if (tipoSombreamento.equals(Constantes.VERTICAL)) {
			int x1 = retangulo.getInicio().getX();
			int y1 = retangulo.getInicio().getY();
			int x2 = retangulo.getFim().getX();
			int y2 = retangulo.getFim().getY();

			int i = 0;
			int x = x1;
			while (x < x2) {
				pontos.addAll(new Reta(new Ponto(x, y1, null), new Ponto(x, y2, null), retangulo.getCor()).getPontos());
				i++;
				x += i * fator;
			}			
		} else if (tipoSombreamento.equals(Constantes.HORIZONTAL)) {
			int x1 = Math.min(retangulo.getInicio().getX(), retangulo.getFim().getX());
			int y1 = Math.min(retangulo.getInicio().getY(), retangulo.getFim().getY());
			int x2 = Math.max(retangulo.getInicio().getX(), retangulo.getFim().getX());
			int y2 = Math.max(retangulo.getInicio().getY(), retangulo.getFim().getY());

			int i = 0;
			int y = y1;
			while (y < y2) {
				pontos.addAll(new Reta(new Ponto(x1, y, null), new Ponto(x2, y, null), retangulo.getCor()).getPontos());
				i++;
				y += i * fator;
			}
		} else if (tipoSombreamento.equals(Constantes.PONTOS)) {
			int x1 = retangulo.getInicio().getX();
			int y1 = retangulo.getInicio().getY();
			int x2 = retangulo.getFim().getX();
			int y2 = retangulo.getFim().getY();

			int area = Math.abs((x2 - x1) * (y2 - y1));
			int maxPontos = (int) (area * fator);
			int totalPontos = 0;

			while (totalPontos < maxPontos) {
				int x = getRandomInt(Math.min(x1, x2), Math.max(x1, x2));
				int y = getRandomInt(Math.min(y1, y2), Math.max(y1, y2));

				pontos.add(new Ponto(x, y, retangulo.getCor()));

				totalPontos++;
			}
		}

		return pontos;
	}

	/**
	 * Metodo responsavel por realizar o sombreamento sobre um setor
	 * 
	 * @param Setor setor
	 * @param String tipoSombreamento
	 * @param double fator
	 * 
	 * @return Pontos
	 */
	private Pontos criaSombreamentoSetor(Setor setor, String tipoSombreamento, double fator) {
		Pontos pontos = new Pontos();

		if (tipoSombreamento.equals(Constantes.CIRCULAR)) {
			int raio = 1;			
			int i = 0;

			while (raio < setor.getRaio()) {
				pontos.addAll(new Circulo(setor.getCentro(), raio, setor.getAnguloInicial(), setor.getAnguloFinal(), setor.getCor()).getPontos());
				i++;
				raio += i * fator;
			}			
		} else if (tipoSombreamento.equals(Constantes.RADIAL)) {
			Ponto centro = setor.getCentro();
			int x1 = centro.getX();
			int y1 = centro.getY();
			int raio = setor.getRaio();

			int anguloInicial = (int) Math.toDegrees(setor.getAnguloInicial());
			int anguloFinal = (int) Math.toDegrees(setor.getAnguloFinal());

			int i = 0;
			int angulo = anguloInicial;
			while (angulo < anguloFinal) {
				Ponto p = new Ponto((int) (x1 + (raio * Math.cos(Math.toRadians(angulo)))), (int) (y1 - (raio * Math.sin(Math.toRadians(angulo)))), null);
				pontos.addAll(new Reta(centro, p, setor.getCor()).getPontos());
				i++;
				angulo += i * fator;
			}
		}
		return pontos;
	}

	/**
	 * Metodo responsavel por gerar um valor aleatorio, que sera utilizado
	 * para determinar o posicionamento dos pontos do sombreamento
	 * 
	 * @param int min
	 * @param int max
	 * 
	 * @return int
	 */
	private int getRandomInt(int min, int max) {
		int n = max - min + 1;
		int i = Math.abs(random.nextInt() % n);

		return min + i;		
	}

}
